AWS CI/CD for Amazon ECS ハンズオンをやってみた
概要
AWS CI/CD for Amazon ECS ハンズオンをやってみました。
ハンズオンは下記の3本立てです。3時間程度で終わりました。
- サンプルアプリのコンテナイメージ作成
- AWS Fargate環境構築とコンテナ実行
- CI/CDのパイプライン作成
ハンズオンを進めながら個人的なメモを補足した内容です。実際のハンズオン資料を見ながら作業をすすめ補足資料になればよいなと思っています。 CodeBuild時にDocker Hubのレートリミットに引っかかるとつまづくと思うのでそこの回避方法を載せています。
まず、AWS Fargateとは
ハンズオン1
Fargateでコンテナを実行するまでの前準備する内容です。
ハンズオン資料より
VPC、ALB作成
ハンズオンの手順ではVPCはCloudFormationで構築します。コードはハンズオン資料内にダウンロードリンクがあります。ALBとセキュリティグループはマネジメントコンソールから作成します。 ハンズオン終了後リソースを削除するのが手間なのですべてCloudFormationで作成しました。ハンズオンの資料の最後には作成したリソースの削除方法もまとまっているため手動でリソースを作成しても消し忘れない安心設計ではあります。
bigmuramura/cfn-cicd-ecs-handson
Dockerアプリ開発
ハンズオンの手順ではECRにリポジトリを作成します。ハンズオンはマネジメントコンソールから作成します。こちらもついでにCloudFormationで作成しました。
AWS Cloud9環境の構築
Cloud9を用意するのが手間だったのでローカルではじめました。Dockerfile
とsrc/index.php
を適当なディレクトリ配下に作成します。
実行環境
> docker -v Docker version 20.10.0, build 7287ab3
Dockerfile作成と、PHPサンプルアプリ作成
> tree . ├── Dockerfile └── src └── index.php
FROM php:7.4.0-apache COPY src/ /var/www/html/
ホスト名を返すページを作成します。
<!DOCTYPE html> <html lang="ja"> <head> <title>PHP Sample</title> </head> <body> <?php echo gethostname(); ?> </body> </html>
Dockerイメージ作成、コンテナ起動
> docker build -t php-sample . > docker run --rm -p 8080:80 -d php-sample:latest > docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a72fd7ff71f1 php-sample:latest "docker-php-entrypoi…" 4 seconds ago Up 3 seconds 0.0.0.0:8080->80/tcp cool_almeida
WEBブラウザでアクセス
curl叩いた様子
curl localhost:8080 <!DOCTYPE html> <html lang="ja"> <head> <title>PHP Sample</title> </head> <body> a72fd7ff71f1 </body> </html>
コンテナ停止
> docker stop cool_almeida
マネジメントコンソールから作成したリポジトリのプッシュコマンドの表示をクリック
表示された1番目のコマンドを実行
# ECRへログイン > aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 1234567890.dkr.ecr.us-east-1.amazonaws.com Login Succeeded
2番目のコマンドはハンズオン途中でイメージ作成済みのため使いません。
表示された3番目のコマンドのdocker tag
の後のphp-sample:latest
部分を変更して実行しました。
リポジトリ名をCloudFormationでhandson-dev-php-sample
作成したためです。2番目のコマンドをそのまま使ってビルドした方がシンプルでした。
# タグ付け > docker tag php-sample:latest 1234567890.dkr.ecr.us-east-1.amazonaws.com/handson-dev-php-sample:latest
表示された4番目のコマンドを実行
# ECRへイメージをPush > docker push 1234567890.dkr.ecr.us-east-1.amazonaws.com/handson-dev-php-sample:latest
リポジトリにイメージが追加されました
ハンズオン2
AWS Fargate環境構築する内容です。
IAMロール作成。
ハンズオン資料通りAWSCodeDeployRoleForECS
のポリシーがアタッチされたロールを作成。
クラスター作成。
ハンズオン資料時のキャプチャには表示されていないContainer Insights
がクラスター作成時に有効にできたのでチェックを入れて作成。
タスク定義作成。
イメージ名の指定のここに入力する文字列は...
ECRからリポジトリ名のコピーボタンを押すとタグも含めコピーされるので貼り付ければOKです。
サービス作成。
ターゲットグループの状態。コンテナが起動しhealthy
になりました。
WEBブラウザからアクセス。
Fargateで起動しているコンテナにALB経由でアクセスすることができました。
ハンズオン3
CI/CDパイプラインの構築する内容です。
ハンズオン資料より
CodeCommitリポジトリのクローン。git-remote-codecommit
を使用するたためHTTPSのクローン(GRC)のURLを使用しています。
> git clone codecommit::us-east-1://php-sample Cloning into 'php-sample'... warning: You appear to have cloned an empty repository.
ハンズオン1で作成したファイルをコピーしました。
> tree . ├── Dockerfile └── src └── index.php
buildspec.yml新規作成。
pre_buildフェーズ
- ECRリポジトリへログイン
handson-dev-php-sample
リポジトリのURIを変数に設定- イメージタグとしてビルドIDのPrefixを利用
buildフェーズ
- Dockerイメージのビルド
- タグ付け
post_buildフェーズ
- ビルドしたイメージをECRへPush
artifactsフェーズ
- CodePipelineで後続フェーズにタグ情報を渡すためのアウトプット
version: 0.2 phases: pre_build: commands: - $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email) - REPOSITORY_URI=1234567890.dkr.ecr.us-east-1.amazonaws.com/handson-dev-php-sample - IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7) build: commands: - docker build -t $REPOSITORY_URI:latest . - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG post_build: commands: - docker push $REPOSITORY_URI:latest - docker push $REPOSITORY_URI:$IMAGE_TAG - printf '{"Version":"1.0","ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json artifacts: files: imageDetail.json
appspec.yml新規作成。
version: 0.0 Resources: - TargetService: Type: AWS::ECS::Service Properties: TaskDefinition: "<TASK_DEFINITION>" LoadBalancerInfo: ContainerName: "php-sample-fargate" ContainerPort: 80
taskdef.json新規作成。
image:
の項目を<IMAGE1_NAME>
に修正する。
# 抜粋 "volumesFrom": [], "stopTimeout": null, "image": <IMAGE1_NAME>, "startTimeout": null, "firelensConfiguration": null,
最終的なディレクトリ構成はこちら。
> tree . ├── Dockerfile ├── appspec.yml ├── buildspec.yml ├── src │ └── index.php └── taskdef.json
CodeCommitのリポジトリへPush
> git add -A > git commit -m "first commit” > git push origin master
パイプライン作成
資料通り進めていけばよいのですが運が悪いとCodeBuildで失敗します。
下記エラーでCodeBuild失敗!!
toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit
簡単な対処としてはハンズオンの中でNAT Gatewayを作成しているためCodeBuildをVPC内で実行しNAT GatewayのEIP経由でDoceker Hubへアクセスさせてレートリミットを回避します。
CodeBuildからビルドプロジェクトを選択し、php-sample-buildを編集します。
VPCとPrivateSubnetを選択し、セキュリティグループはアウトバウンドが空いていればよいのでハンズオンの中で作成したセキュリティグループを流用します。
手動でパイプラインを再実行させます。
今度はCodeBuild成功しました。
CodeDeployによりBlue/Greenデプロイされ、ALBのURLからアクセスしました。コンテナのプライベートIPが変わっているため新しいコンテナに切り替わったことがわかります。ハンズオンの設定ではコンテナは常時1台しか起動していません。
おわりに
一度手を動かしてみるとタスク定義やサービスなど用語だけ聞いてもピンとこないものが理解しやすくなるかと思います。ハンズオン1の準備さえ終わればすぐにFargateで動かせるので興味あれば手を動かしてみることをオススメします。
以上、網走の大村でした。
参考
AWS でデプロイの自動化を実現するベストプラクティスをグラレコで解説 - builders.flash☆ - 変化を求めるデベロッパーを応援するウェブマガジン | AWS